'''
降低维度，将64维降低到2维再进行处理
自己编写版本
'''
import matplotlib.pyplot as plt
from sklearn.datasets import load_digits
from sklearn.manifold import Isomap
import numpy as np
import math
from sklearn.metrics import accuracy_score,confusion_matrix

#加载数据
digits = load_digits()
location_yangben = digits.data #取出样本坐标值
lables_yangben = digits.target #取出样本标签值

class_number = 10              #目标分成几类，即最终分出的类别个数
iteration_number = 500         #计算的迭代步数
wucha = 0.000001               #可接受误差值
#运用流形降维方法将图像降至二维
iso = Isomap(n_neighbors=5, n_components=2)                       #取临近参数为5，降至二维
jiangwei_location_yangben = iso.fit_transform(digits.data)        #fit入数据

#定义sigmoid 函数
def sigmoid(z):
    return 1.0 / (1 + np.exp(-z))

#按照类的模式封装Logistic
class Logistic:
    def __init__(self,data,label):                 #逻辑回归类定义
        self.data = data                         #数据位置点导入类
        self.label = label                       #数据标签导入类
        self.alpha = 0.05                        #步长
        self.data_number,self.n = np.shape(data) #数据大小以及维度
        self.weight = np.ones((class_number,self.n))       #初始化存储权重的矩阵
        self.b = np.zeros(class_number)                    #初始化存储偏置的矩阵

    def train(self):                             #多分类模型参数训练
        for j in range(class_number):
            lables_ = np.copy(self.label)        #取出标签值

            for i in range(self.data_number):    #取出特定类别标签
                if lables_[i] == j:
                    lables_[i] = 1
                else:
                    lables_[i] = 0

            for i_1 in range(iteration_number):  #开始进行梯度计算迭代
                error_0 = math.inf               #初始将误差设为无穷大
                index_data = list(range(self.data_number))  #取出数据标签
                for i_2 in range(self.data_number):
                    random_index = int(np.random.uniform(0,len(index_data)))  #随机取出标签值进行迭代，既可以提高计算效率，又可以避免异常数据的影响
                    error = lables_[random_index] - sigmoid(np.dot(self.data[random_index],self.weight[j])+self.b[j])
                    self.weight[j] = self.weight[j] + self.alpha * error * self.data[random_index]
                    self.b[j] = self.b[j] + self.alpha * error  #梯度上升参数迭代公式
                    del [index_data[random_index]]
                    if abs(error - error_0) < wucha:            #当结果趋于稳定，结束循环
                        break
                    error_0 = error

    def predict(self,predict_data):                             #预测函数
        label = np.zeros(np.shape(predict_data)[0])
        output = np.zeros(class_number)
        output = list(output)

        for i in range(len(label)):                             #我们将每种类别中的权重取值与数据放入S函数中求其概率，概率最大的作为最终结果
            for j in range(class_number):
                output[j] = sigmoid(sum(predict_data[i,:] * self.weight[j,:] + self.b[j]))
            label[i] = output.index(max(output))

        return label

#取出训练样本以及测试样本
num = len(location_yangben)  #样本总个数
num_train = int(num * 0.7)   #训练样本占70%
num_test = num - num_train   #测试样本占30%

location_yangben_train = location_yangben[:num_train,:]  #训练样本点位置
location_yangben_test = location_yangben[num_train:,:]   #测试样本点位置

lables_yangben_train = lables_yangben[:num_train]        #训练样本点标签
lables_yangben_test = lables_yangben[num_train:]         #测试样本点标签

#进行聚类
logistic =Logistic(location_yangben_train,lables_yangben_train)
logistic.train()
train_output = logistic.predict(location_yangben_train)
test_output = logistic.predict(location_yangben_test)

#输出精度
train_acc =accuracy_score(train_output,lables_yangben_train)
print("LR聚类（编写版）训练数据精确度（数据降维版）",train_acc)
test_acc = accuracy_score(test_output,lables_yangben_test)
print("LR聚类（编写版）测试数据精确度（数据降维版）",test_acc)

#混淆矩阵
cm = confusion_matrix(lables_yangben_test,test_output)

plt.matshow(cm)
plt.title(u'Confusion Matrix')
plt.colorbar()
plt.ylabel(u'Groundtruth')
plt.xlabel(u'Predict')
plt.show()


